Micron Document
πŸŽ–οΈGitΠ―Ρ€Π°πŸŽ–οΈ

Commit c16c33f6206afcf8797f8519da34e7bb7b30c913


Parents : 9f76631
Author : renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signature : Signature validation error
Date : 2026-08-11T15:17:22Z
Committer : GitHub <noreply@github.com>
Date : 2026-08-11T15:17:22Z

chore(deps): update gradle to v9.7.0 (#6589)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: James Rich <james.a.rich@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

Changes
Diff

diff --git a/.github/actions/gradle-setup/action.yml b/.github/actions/gradle-setup/action.yml
index 96108320b0..f0e4e90a24 100644
--- a/.github/actions/gradle-setup/action.yml
+++ b/.github/actions/gradle-setup/action.yml
@@ -140,6 +140,9 @@ runs:
# Develocity measured 100% CC miss (~52s config/build) before this. Runs after Setup
# Gradle so GRADLE_ENCRYPTION_KEY is exported. No sha in the key: unchanged build files
# hit exactly and skip the save; restore-keys is the self-heal for stale entries.
+ # The wrapper hash is its own restore-key segment: a stale same-version entry is a
+ # graceful CC miss, but an entry written by a DIFFERENT Gradle version can crash
+ # fingerprint deserialization outright (seen on 9.6.1 entries under 9.7.0).
- name: Cache Gradle configuration-cache
# Gates: opted in; key present (undecryptable otherwise β€” keeps keyless fork PRs off
# these entries); not merge_group (throwaway cache scope).
@@ -147,6 +150,6 @@ runs:
uses: actions/cache@v6
with:
path: ${{ github.workspace }}/.gradle/configuration-cache
- key: gradle-cc-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}${{ inputs.cache_key_suffix && format('-{0}', inputs.cache_key_suffix) || '' }}-${{ hashFiles('settings.gradle.kts', '**/build.gradle.kts', 'build-logic/**', 'gradle/*.gradle', 'gradle/libs.versions.toml', 'gradle/wrapper/gradle-wrapper.properties', 'gradle.properties', 'config.properties', '.github/ci-gradle.properties') }}
+ key: gradle-cc-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}${{ inputs.cache_key_suffix && format('-{0}', inputs.cache_key_suffix) || '' }}-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}-${{ hashFiles('settings.gradle.kts', '**/build.gradle.kts', 'build-logic/**', 'gradle/*.gradle', 'gradle/libs.versions.toml', 'gradle.properties', 'config.properties', '.github/ci-gradle.properties') }}
restore-keys: |
- gradle-cc-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}${{ inputs.cache_key_suffix && format('-{0}', inputs.cache_key_suffix) || '' }}-
+ gradle-cc-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}${{ inputs.cache_key_suffix && format('-{0}', inputs.cache_key_suffix) || '' }}-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}-

diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml
index c7bf398ff2..0b5a5b9f13 100644
--- a/.github/workflows/docs-deploy.yml
+++ b/.github/workflows/docs-deploy.yml
@@ -110,7 +110,7 @@ jobs:
--baseurl /${{ github.event.repository.name }}/main &
jekyll_pid=$!
if [ "$BUILD_DOKKA" = "true" ]; then
- ./gradlew dokkaGeneratePublicationHtml --no-configuration-cache
+ ./gradlew dokkaGeneratePublicationHtml --no-isolated-projects --no-configuration-cache
else
echo "No Dokka-relevant changes β€” skipping API reference rebuild."
fi

diff --git a/.github/workflows/docs-release.yml b/.github/workflows/docs-release.yml
index 997a9f3809..114e63e03b 100644
--- a/.github/workflows/docs-release.yml
+++ b/.github/workflows/docs-release.yml
@@ -104,7 +104,7 @@ jobs:
# Dokka API reference (/api/) β€” production releases only.
- name: Build Dokka HTML documentation
if: steps.version.outputs.is_production == 'true'
- run: ./gradlew dokkaGeneratePublicationHtml --no-configuration-cache
+ run: ./gradlew dokkaGeneratePublicationHtml --no-isolated-projects --no-configuration-cache
- name: Compile Jekyll Sites
env:

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b4b91480b5..59f74eb01a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -459,7 +459,7 @@ jobs:
# are runtime-only and would be missed by :assemble).
- name: Generate Flatpak Sources
run: >
- ./gradlew --no-build-cache --no-configuration-cache
+ ./gradlew --no-build-cache --no-isolated-projects --no-configuration-cache -Pmeshtastic.flatpakSources=true
-Dgradle.user.home=${{ runner.temp }}/flatpak-gradle-home
:desktopApp:packageUberJarForCurrentOS :captureFlatpakSources

diff --git a/.github/workflows/reusable-check.yml b/.github/workflows/reusable-check.yml
index f23e8b412f..451940b096 100644
--- a/.github/workflows/reusable-check.yml
+++ b/.github/workflows/reusable-check.yml
@@ -131,7 +131,9 @@ jobs:
cache_configuration_cache: 'true' # VERSION_CODE pinned -> entries actually reuse
- name: Screenshot Test Validation
- run: ./gradlew :screenshot-tests:validateDebugScreenshotTest -Pci=true
+ # --no-isolated-projects: AGP's screenshot plugin iterates BuildServicesRegistry at
+ # execution time, which Isolated Projects forbids (fatal since Gradle 9.7).
+ run: ./gradlew :screenshot-tests:validateDebugScreenshotTest -Pci=true --no-isolated-projects
- name: Upload screenshot diff report
if: failure()
@@ -450,7 +452,9 @@ jobs:
echo "VERSION_NAME=${BASE}-SNAPSHOT" >> "$GITHUB_ENV"
- name: Build Android APKs
- run: ./gradlew androidApp:assembleFdroidDebug androidApp:assembleGoogleDebug -Pci=true --parallel --configuration-cache --continue
+ # --no-isolated-projects: the dependency-graph plugin injected by setup-gradle force-resolves
+ # via allprojects{}, which Isolated Projects forbids (fatal since Gradle 9.7).
+ run: ./gradlew androidApp:assembleFdroidDebug androidApp:assembleGoogleDebug -Pci=true --parallel --configuration-cache --no-isolated-projects --continue
- name: Upload debug artifact
if: ${{ inputs.upload_artifacts }}
@@ -574,7 +578,7 @@ jobs:
# runtime classpath. :assemble alone would miss runtime-only deps (skiko, ktor-cio, …).
- name: Generate Flatpak Sources
run: >
- ./gradlew --no-build-cache --no-configuration-cache
+ ./gradlew --no-build-cache --no-isolated-projects --no-configuration-cache -Pmeshtastic.flatpakSources=true
-Dgradle.user.home=${{ runner.temp }}/flatpak-gradle-home
:desktopApp:packageUberJarForCurrentOS :captureFlatpakSources

diff --git a/.github/workflows/scheduled-baseline.yml b/.github/workflows/scheduled-baseline.yml
index e48fff2084..d15c54594a 100644
--- a/.github/workflows/scheduled-baseline.yml
+++ b/.github/workflows/scheduled-baseline.yml
@@ -65,7 +65,9 @@ jobs:
# --no-configuration-cache: the underlying connectedGoogleNonMinifiedReleaseAndroidTest task is not
# config-cache serializable (SeparateTestModuleTestData / ResolutionBackedFileCollection), and the
# project enables org.gradle.configuration-cache by default β€” same workaround used in reusable-check.yml.
- script: ./gradlew :androidApp:generateGoogleReleaseBaselineProfile -Pci=true --no-configuration-cache
+ # --no-isolated-projects must accompany it: Isolated Projects implies the configuration cache, and
+ # Gradle 9.7+ hard-errors when the cache is disabled while Isolated Projects is on.
+ script: ./gradlew :androidApp:generateGoogleReleaseBaselineProfile -Pci=true --no-isolated-projects --no-configuration-cache
- name: Detect baseline profile changes
id: baseline

diff --git a/.github/workflows/verify-flatpak.yml b/.github/workflows/verify-flatpak.yml
index c27d19f7ee..c878792c6d 100644
--- a/.github/workflows/verify-flatpak.yml
+++ b/.github/workflows/verify-flatpak.yml
@@ -51,7 +51,7 @@ jobs:
- name: Generate flatpak-sources.json
run: |
- ./gradlew --no-build-cache --no-configuration-cache \
+ ./gradlew --no-build-cache --no-isolated-projects --no-configuration-cache -Pmeshtastic.flatpakSources=true \
-Dgradle.user.home="$RUNNER_TEMP/flatpak-gradle-home" \
:desktopApp:packageUberJarForCurrentOS :captureFlatpakSources
cp build/flatpak-sources.json flatpak-sources.json

diff --git a/.skills/project-overview/SKILL.md b/.skills/project-overview/SKILL.md
index c8732a3a07..13b6abef4e 100644
--- a/.skills/project-overview/SKILL.md
+++ b/.skills/project-overview/SKILL.md
@@ -74,5 +74,5 @@ Agents **MUST** perform these steps automatically at the start of every session
## Troubleshooting
- **Build Failures:** Check `gradle/libs.versions.toml` for dependency conflicts.
-- **Configuration Cache:** Add `--no-configuration-cache` if cache-related issues persist.
+- **Configuration Cache:** Add `--no-isolated-projects --no-configuration-cache` if cache-related issues persist. Both flags are required: Isolated Projects (on by default here) implies the configuration cache, and Gradle 9.7+ fails the build if you disable the cache without also disabling Isolated Projects.
- **Koin Injection Failures:** Verify the component is included in `AppKoinModule`.

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e6b43ec686..03416cdb05 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -15,7 +15,7 @@ Thank you for your interest in contributing to Meshtastic-Android! We welcome co
- Follow the [Kotlin Coding Conventions](https://kotlinlang.org/docs/coding-conventions.html) for Kotlin code.
- Use Android Studio's default formatting settings.
- We use [spotless](https://github.com/diffplug/spotless) for automated code formatting. You can run `./gradlew spotlessApply` to format your code automatically.
- - You can also run `./gradlew spotlessInstallGitPrePushHook --no-configuration-cache` to install a pre-push Git hook that will run a `spotlessCheck`.
+ - You can also run `./gradlew spotlessInstallGitPrePushHook --no-isolated-projects --no-configuration-cache` to install a pre-push Git hook that will run a `spotlessCheck`.
- Write clear, descriptive variable and function names.
- Add comments where necessary, especially for complex logic.
- Keep methods and classes focused and concise.

diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts
index 42f6820e00..fdd068c550 100644
--- a/build-logic/convention/build.gradle.kts
+++ b/build-logic/convention/build.gradle.kts
@@ -74,6 +74,10 @@ tasks {
}
}
+// Isolated Projects forbids reaching into another project; ".." escapes the included build
+// to the repo root, where the shared config lives.
+val repoConfigDir = isolated.rootProject.projectDirectory.dir("../config")
+
spotless {
ratchetFrom("origin/main")
kotlin {
@@ -81,22 +85,20 @@ spotless {
// secrets_gradle_plugin is vendored third-party code (Apache-2.0) keeping Google's header.
targetExclude("**/build/**/*.kt", "**/secrets_gradle_plugin/**")
ktfmt().kotlinlangStyle().configure { it.setMaxWidth(120) }
- ktlint(libs.versions.ktlint.get())
- .setEditorConfigPath(rootProject.file("../config/spotless/.editorconfig").path)
- licenseHeaderFile(rootProject.file("../config/spotless/copyright.kt"))
+ ktlint(libs.versions.ktlint.get()).setEditorConfigPath(repoConfigDir.file("spotless/.editorconfig").asFile.path)
+ licenseHeaderFile(repoConfigDir.file("spotless/copyright.kt").asFile)
}
kotlinGradle {
target("**/*.gradle.kts")
ktfmt().kotlinlangStyle().configure { it.setMaxWidth(120) }
- ktlint(libs.versions.ktlint.get())
- .setEditorConfigPath(rootProject.file("../config/spotless/.editorconfig").path)
- licenseHeaderFile(rootProject.file("../config/spotless/copyright.kts"), "(^(?![\\/ ]\\*).*$)")
+ ktlint(libs.versions.ktlint.get()).setEditorConfigPath(repoConfigDir.file("spotless/.editorconfig").asFile.path)
+ licenseHeaderFile(repoConfigDir.file("spotless/copyright.kts").asFile, "(^(?![\\/ ]\\*).*$)")
}
}
detekt {
toolVersion = libs.versions.detekt.get()
- config.setFrom(rootProject.file("../config/detekt/detekt.yml"))
+ config.setFrom(repoConfigDir.file("detekt/detekt.yml").asFile)
buildUponDefaultConfig = true
allRules = false
baseline = file("detekt-baseline.xml")

diff --git a/desktopApp/build.gradle.kts b/desktopApp/build.gradle.kts
index b48bb9aa02..14c6fa8f7f 100644
--- a/desktopApp/build.gradle.kts
+++ b/desktopApp/build.gradle.kts
@@ -150,7 +150,8 @@ compose.desktop {
obfuscate.set(false) // Open-source project β€” obfuscation adds no value
optimize.set(true)
configurationFiles.from(
- rootProject.file("config/proguard/shared-rules.pro"),
+ // Isolated Projects forbids reaching into the root project via rootProject.file().
+ isolated.rootProject.projectDirectory.file("config/proguard/shared-rules.pro").asFile,
project.file("proguard-rules.pro"),
)
}

diff --git a/feature/docs/build.gradle.kts b/feature/docs/build.gradle.kts
index ec8f95a3d2..bed5fdd299 100644
--- a/feature/docs/build.gradle.kts
+++ b/feature/docs/build.gradle.kts
@@ -62,8 +62,9 @@ val syncDocsToComposeResources =
description = "Syncs docs/en/ markdown source into composeResources for in-app bundling"
group = "docs"
- val docsEnDir = rootProject.layout.projectDirectory.dir("docs/en")
- val screenshotsDir = rootProject.layout.projectDirectory.dir("docs/assets/screenshots")
+ // isolated.rootProject: Isolated Projects forbids reaching through rootProject.layout.
+ val docsEnDir = isolated.rootProject.projectDirectory.dir("docs/en")
+ val screenshotsDir = isolated.rootProject.projectDirectory.dir("docs/assets/screenshots")
val composeResourcesTarget = layout.projectDirectory.dir("src/commonMain/composeResources/files/docs")
from(docsEnDir) {
@@ -100,7 +101,7 @@ val syncTranslatedDocsToComposeResources =
description = "Syncs Crowdin-translated docs into locale-qualified composeResources"
group = "docs"
- val docsDir = rootProject.layout.projectDirectory.dir("docs")
+ val docsDir = isolated.rootProject.projectDirectory.dir("docs")
val targetBase = layout.projectDirectory.dir("src/commonMain/composeResources/files")
from(docsDir) {

diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4e7e897967..63232e1d10 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -2,8 +2,8 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
# -bin: nothing here reads -all's docs/sources. Update sha256 with the URL on upgrades
# (official .sha256 sits next to the distribution; renovate does both).
-distributionSha256Sum=9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14
-distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
+distributionSha256Sum=84fbba45c7f4c64abc77460e1c00f541e9f960e3c7ed2538f1ede19eacd873ae
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip
networkTimeout=30000
retries=3
retryBackOffMs=500

diff --git a/scripts/verify-flatpak/desktop-offline.yaml b/scripts/verify-flatpak/desktop-offline.yaml
index 4ea95f4842..084d2cf68d 100644
--- a/scripts/verify-flatpak/desktop-offline.yaml
+++ b/scripts/verify-flatpak/desktop-offline.yaml
@@ -99,8 +99,8 @@ modules:
- type: file
# Must be the EXACT distribution from gradle-wrapper.properties (version AND
# -bin flavor) β€” distributionSha256Sum verifies this file. Update together.
- url: https://services.gradle.org/distributions/gradle-9.6.1-bin.zip
- sha256: 9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14
+ url: https://services.gradle.org/distributions/gradle-9.7.0-bin.zip
+ sha256: 84fbba45c7f4c64abc77460e1c00f541e9f960e3c7ed2538f1ede19eacd873ae
dest: "gradle/wrapper"
dest-filename: "gradle-bin.zip"
- flatpak-sources.json

diff --git a/scripts/verify-flatpak/verify.sh b/scripts/verify-flatpak/verify.sh
index 697c7c0e09..7557d337e2 100755
--- a/scripts/verify-flatpak/verify.sh
+++ b/scripts/verify-flatpak/verify.sh
@@ -79,7 +79,7 @@ if [[ $SKIP_REGEN -eq 0 ]]; then
rm -rf "$GRADLE_HOME_ISOLATED"
# The settings plugin (org.meshtastic.flatpak.sources.settings) captures URLs from
# build start β€” no init script or -I flag needed.
- (cd "$REPO_ROOT" && ./gradlew --no-build-cache --no-configuration-cache \
+ (cd "$REPO_ROOT" && ./gradlew --no-build-cache --no-isolated-projects --no-configuration-cache -Pmeshtastic.flatpakSources=true \
-Dgradle.user.home="$GRADLE_HOME_ISOLATED" \
:desktopApp:packageUberJarForCurrentOS :captureFlatpakSources)
cp "$REPO_ROOT/build/flatpak-ops-sources.json" "$SOURCES_JSON"

diff --git a/scripts/verify-rb.sh b/scripts/verify-rb.sh
index 541de86f06..e7eff3e662 100755
--- a/scripts/verify-rb.sh
+++ b/scripts/verify-rb.sh
@@ -12,11 +12,11 @@ trap 'rm -rf "$WORKDIR"' EXIT
echo "── Step 1: Verify aboutlibraries.json determinism ──"
rm -f androidApp/src/main/resources/aboutlibraries.json
-./gradlew :androidApp:exportLibraryDefinitions -Pci=true --no-configuration-cache
+./gradlew :androidApp:exportLibraryDefinitions -Pci=true --no-isolated-projects --no-configuration-cache
cp androidApp/src/main/resources/aboutlibraries.json "$WORKDIR/aboutlibraries-run1.json"
rm -f androidApp/src/main/resources/aboutlibraries.json
-./gradlew :androidApp:exportLibraryDefinitions -Pci=true --no-configuration-cache --rerun-tasks
+./gradlew :androidApp:exportLibraryDefinitions -Pci=true --no-isolated-projects --no-configuration-cache --rerun-tasks
cp androidApp/src/main/resources/aboutlibraries.json "$WORKDIR/aboutlibraries-run2.json"
if ! diff -q "$WORKDIR/aboutlibraries-run1.json" "$WORKDIR/aboutlibraries-run2.json"; then
@@ -27,7 +27,7 @@ fi
echo "βœ… aboutlibraries.json is deterministic"
echo "── Step 2: Build fdroid release APK ──"
-./gradlew :androidApp:assembleFdroidRelease -Pci=true -Pmeshtastic.disableAbiSplits=true --no-configuration-cache
+./gradlew :androidApp:assembleFdroidRelease -Pci=true -Pmeshtastic.disableAbiSplits=true --no-isolated-projects --no-configuration-cache
APK=$(find androidApp/build/outputs/apk/fdroid/release -name "*.apk" | head -1)
if [ -z "$APK" ]; then

diff --git a/settings.gradle.kts b/settings.gradle.kts
index 00bd029b1d..6cafdc3117 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -36,7 +36,16 @@ plugins {
// Develocity + CCUD + build cache; shared with build-logic, versions from the catalog.
id("meshtastic.develocity")
id("org.gradle.toolchains.foojay-resolver") version "1.0.0"
- id("org.meshtastic.flatpak.sources.settings") version "0.1.5"
+ // Applied on demand only β€” see below.
+ id("org.meshtastic.flatpak.sources.settings") version "0.1.5" apply false
+}
+
+// The flatpak-sources plugin reads Gradle.extensions, which Isolated Projects forbids; Gradle 9.7
+// enforces that and fails every task in the build. Only :captureFlatpakSources needs the plugin, and
+// its callers already pass --no-isolated-projects, so gate it on an opt-in property. Remove the gate
+// once org.meshtastic.flatpak.sources.settings > 0.1.5 ships an Isolated-Projects-safe release.
+if (providers.gradleProperty("meshtastic.flatpakSources").isPresent) {
+ pluginManager.apply("org.meshtastic.flatpak.sources.settings")
}
@Suppress("UnstableApiUsage")

Served by rngit 1.5.0 - Generated in 0.25s